#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 11-Nov-09 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;

using Thn;
#endregion

namespace Thn.Interface.Vcl
{
    /// <summary>
    /// A helper class for handling popup routines.
    /// </summary>
#if DEBUG
    public
#else
    public
#endif
 class PopupController : IPopupController
    {
        #region Fields
        #endregion

        #region Properties

        #region Data
        private object mData;
        /// <summary>
        /// Gets/Sets the information that the popup editor and host are interested in
        /// </summary>
        [Browsable(false), DefaultValue(null)]
        public object Data
        {
            get { return mData; }
            set { mData = value; }
        }
        #endregion

        #region Host
        private Control mHost;
        /// <summary>
        /// Gets/Sets the original control that owns this popup
        /// </summary>
        [Browsable(true), DefaultValue(null), Category("Appearance"), Description("The control that this popup attaches to")]
        public Control Host
        {
            get { return mHost; }
            set { mHost = value; }
        }
        #endregion

        #region Editor

        #region Editor
        private IPopupEditor mEditor;
        /// <summary>
        /// Gets/Sets the editor that is associated with this popup
        /// </summary>
        [Browsable(false), DefaultValue(null)]
        public IPopupEditor Editor
        {
            get { return mEditor; }
            set { mEditor = value; }
        }
        #endregion

        #region Editor Type
        private Type mEditorType;
        /// <summary>
        /// Gets/Sets type of editor. This is used for instantiate a new editor before showing
        /// </summary>
        [Browsable(false), DefaultValue(null)]
        public Type EditorType
        {
            get { return mEditorType; }
            set { mEditorType = value; }
        }
        #endregion

        #region Get Editor
        /// <summary>
        /// Gets the editor used for showing popup
        /// </summary>
        IPopupEditor GetEditor()
        {
            IPopupEditor result = null;

            if (mEditorType != null)
            {
                bool createNew = false;

                if (mCreateEditorOnce)
                {
                    if (mEditor == null) createNew = true;
                }
                else createNew = true;

                if (createNew)
                {
                    result = (IPopupEditor)Activator.CreateInstance(mEditorType);
                    mEditor = result;
                }
            }
            else result = mEditor;

            return result;
        }
        #endregion

        #region Create Editor Once
        private bool mCreateEditorOnce = false;
        /// <summary>
        /// When true, the editor will be created only once. Default is false, a new editor is created each time the popup is shown.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Behavior"), Description("When true, the editor will be created only once")]
        public bool CreateEditorOnce
        {
            get { return mCreateEditorOnce; }
            set { mCreateEditorOnce = value; }
        }
        #endregion

        #endregion

        #region Form
        private PopupFormBase mForm;
        /// <summary>
        /// Gets/Sets the form that will contains the popup editor
        /// </summary>
        [Browsable(false), DefaultValue(null), Category("Appearance"), Description("the form that will contains the popup editor")]
        public PopupFormBase Form
        {
            get { return mForm; }
            set { mForm = value; }
        }
        #endregion

        #region Location
        private Point mLocation = Point.Empty;
        /// <summary>
        /// Gets/Sets offset to location (top left) of owner control
        /// </summary>
        public Point Location
        {
            get { return mLocation; }
            set { mLocation = value; }
        }
        #endregion

        #region Width
        private int mWidth = 0;
        /// <summary>
        /// Gets/Sets the popup-width.
        /// <para>Default is 0. (width is determined by the editor)</para>
        /// </summary>
        [Browsable(true), DefaultValue(0), Category("Appearance"), Description("Popup height")]
        public int Width
        {
            get { return mWidth; }
            set { mWidth = value; }
        }
        #endregion

        #region Height
        private int mHeight = 0;
        /// <summary>
        /// Gets/Sets the popup-height.
        /// <para>Default is 0. (height is determined by the editor)</para>
        /// </summary>
        [Browsable(true), DefaultValue(0), Category("Appearance"), Description("Popup height")]
        public int Height
        {
            get { return mHeight; }
            set { mHeight = value; }
        }
        #endregion

        #region Is Popping
        /// <summary>
        /// Checks whether the popup is being shown
        /// </summary>
        public bool IsPopping
        {
            get
            {
                bool result = false;
                if (mHelper != null) result = mHelper.IsPopping;
                return result;
            }
        }
        #endregion

        #region Handle Escape Key
        private bool mHandleEscapeKey = true;
        /// <summary>
        /// Gets/Sets whether the popup automatically cancels when user press Escape key.
        /// <para>Default is true</para>
        /// </summary>
        [Browsable(true), DefaultValue(true), Category("Behavior"), Description("Popup automatically cancels when user press Escape key")]
        public bool HandleEscapeKey
        {
            get { return mHandleEscapeKey; }
            set { mHandleEscapeKey = value; }
        }
        #endregion

        #region Drop Shadow
        private bool mDropShadow = true;
        /// <summary>
        /// Shows a soft shadow at edge of popup form.
        /// <para>Default is true</para>
        /// </summary>
        [Browsable(true), DefaultValue(true), Category("Appearance"), Description("Shows a soft shadow at edge of popup form.")]
        public bool DropShadow
        {
            get { return mDropShadow; }
            set { mDropShadow = value; }
        }
        #endregion

        #endregion

        #region Events

        #region Accepted
        /// <summary>
        /// This event is raised when the popup form is closed because the user wishes to accept a selection
        /// </summary>
        public event EventHandler Accepted;

        /// <summary>
        /// Raise event Accepted
        /// </summary>
        protected void RaiseAccepted()
        {
            EventHandler handler = Accepted;
            if (handler != null) handler(this, EventArgs.Empty);
        }
        #endregion

        #region Canceled
        /// <summary>
        /// This event is raised when the popup form is closed because the user rejects a selection
        /// </summary>
        public event EventHandler Canceled;

        /// <summary>
        /// Raise event Canceled
        /// </summary>
        protected void RaiseCanceled()
        {
            EventHandler handler = Canceled;
            if (handler != null) handler(this, EventArgs.Empty);
        }
        #endregion

        #endregion

        #region Show
        /// <summary>
        /// Display the popup form
        /// </summary>
        public void Show()
        {
            if (!IsPopping)
            {
                if (mHost == null) throw new NullReferenceException("Property Host is null");
                #region Defensive tracing
                else
                {
                    // The host already initialized.
                }
                #endregion

                //get the neccessary editor
                mEditor = GetEditor();
                if (mEditor == null) PopupException.Publish_NoEditor();
                #region Defensive tracing
                else
                {
                    // the popup editor already created, go on.                    
                }
                #endregion

                //setup popup form
                if (mForm == null) mForm = new PopupFormBase();
                #region Defensive tracing
                else
                {
                    // the form already created.
                }
                #endregion

                mForm.Setup(this, mEditor);
                mForm.DropShadow = mDropShadow;
                mForm.HandleEscapeKey = mHandleEscapeKey;

                //setup editor
                mEditor.Setup(this);

                //display popup form
                ShowPopupForm();
            }
        }
        #endregion

        #region Accept
        /// <summary>
        /// Accept modifications and close the popup
        /// </summary>
        public void Accept()
        {
            if (IsPopping)
            {
                mHelper.ClosePopup();
            }
            #region Defensive tracing
            else
            {
                // the popup was closed.
            }
            #endregion
        }
        #endregion

        #region Cancel
        /// <summary>
        /// Rejects modifications and close the popup
        /// </summary>
        public void Cancel()
        {
            if (IsPopping)
            {
                mHelper.CancelPopup();
            }
            #region Defensive tracing
            else
            {
                // the popup was canceled.
            }
            #endregion
        }
        #endregion

        #region Show Popup Form
        /// <summary>
        /// Show the popup form
        /// </summary>
        void ShowPopupForm()
        {
            PrepareHelper();
            mHelper.SuppressCancelMessageFiltering = true;
            if (mLocation != Point.Empty) mHelper.Location = mLocation;
            mHelper.ShowPopup(Host, Form);            
        }
        #endregion

        #region Popup Helper
        PopupWindowHelper mHelper = null;

        #region Prepare Helper
        /// <summary>
        /// Prepare popup helper
        /// </summary>
        void PrepareHelper()
        {
            if (mHelper == null)
            {
                mHelper = new PopupWindowHelper(mHost);
                mHelper.PopupCancel += new PopupCancelEventHandler(helper_PopupCancel);
                mHelper.PopupClosed += new PopupClosedEventHandler(helper_PopupClosed);
            }
            #region Defensive tracing
            else 
            {
                // the helper already prepared.
            }
            #endregion
        }
        #endregion

        #region Closed
        void helper_PopupClosed(object sender, PopupClosedEventArgs e)
        {
            //ask the popup form to reset
            mForm.Setup(null, null);

            //raise event
            RaiseAccepted();
        }
        #endregion

        #region Canceled
        void helper_PopupCancel(object sender, PopupCancelEventArgs e)
        {
            //ask the popup form to reset
            mForm.Setup(null, null);
            mEditor.Setup(null);

            //raise event
            RaiseCanceled();
        }
        #endregion
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public PopupController()
        { }
        #endregion
    }
}
